package com.cskaoyan.javase.oop3._2inner._5anonymous._0introduction;

/**
 * 匿名内部类的引入
 * 匿名内部类，本质上还是属于定义在别的类内部的一个类。
 * 但区别是：
 * 成员内部类、静态内部类和局部内部类都属于定义了一个类
 * 后续使用还需要基于内部类创建对象。
 * 而匿名内部类和Lambda表达式都是直接通过语法创建了对象,然后直接使用。
 * 所以匿名内部类和Lambda表达式在使用时更方便,更快速,是开发中更常用的内部类,尤其Lambda表达式
 *
 * 最后，在学习匿名内部类和Lambda表达式之前
 * 我们还是要清楚——它们都是特殊的局部内部类。所以一旦访问方法的局部变量，该局部变量需要是一个常量。
 * 而且既然它们是特殊的局部内部类,那么在很多地方都是有相似性的
 *
 *
 * 匿名内部类
 * 匿名对象的含义是这个对象是没有名字，没有引用指向它。
 * 那么匿名内部类，指的就是这个内部类没有名字。
 * 当然普通类,包括内部类当中的成员内部类和静态内部类没法没有名字
 * 所以 匿名内部类指的是"没有名字的局部内部类",是一种特殊的局部内部类。
 *
 *
 * 匿名内部类的语法:
 * new 类名或者接口名(){
 *   // 某类名或接口名的子类的类体
 * };
 * 解释:
 *      1.匿名内部类是特殊的局部内部类,仍然定义在局部变量,一般是在方法内部使用
 *      2.new关键字表示创建对象
 *      3.语法中的"类名"可以写普通类,也可以写抽象类
 *      4.(重点)匿名内部类的语法中,隐含了继承或者实现,new表示创建对象
 *          实际上是表示创建语法中"类名或者接口名"的子类对象
 *      5.(重点)语法结构中的"{}"是什么意思?
 *          就表示语法结构中"类名或者接口名"的子类类体
 *          并且这个子类是没有名字,这个"{}"类体是匿名子类的类体
 *          既然是子类的类体,那么就可以重写方法,以及自定义自身成员.
 *
 * 以上,匿名内部类,更准确的说法应该叫"匿名内部类对象",它的语法结构表示创建了一个匿名子类对象
 *
 * 匿名内部类对象如何使用呢?
 *      1.直接使用
 *          优点是比较简单快捷,并且可以直接访问匿名子类独有的成员
 *          缺点是一次性的,只能用一次
 *
 *      2.用父类引用(语法结构中"类名或者接口名")接收然后再使用
 *          优点是可以重复使用
 *          缺点是稍微麻烦一点,并且不可以访问子类独有成员(真的无法访问,因为无法强转,子类是匿名的)
 *
 * 总结,当为了方便一次性使用某个匿名内部类对象或者需要访问匿名内部类对象独有成员时,采取直接使用的方式
 * 否则就用父类引用接收后再使用
 *
 * @since 15:48
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        // 在局部位置使用匿名内部类创建A的子类对象
        new A() {
            // A的匿名子类的类体
            @Override
            void test() {
                System.out.println("我是A的匿名子类!");
            }

            public void testInner() {
                System.out.println("我是匿名子类独有的方法!");
            }
        }.testInner();

        // 用匿名内部类创建抽象类BaseA的子类对象
        BaseA ba = new BaseA() {
            int num = 10;
            @Override
            public void test() {
                System.out.println("baseA的匿名子类对象!");
            }
        };
        ba.test();
        // 父类引用无法访问子类独有成员
        // ba.num
    }
}

class A {
    void test() {
        System.out.println("我是普通类A");
    }
}

abstract class BaseA {
    public abstract void test();
}

